package com.ys.service.storage.impl;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.ys.entity.storage.*;
import com.ys.enume.finance.TcwOperateFrozenRunningEnum;
import com.ys.mapper.storage.TccPreAllocatePublishMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ys.config.MenuId;
import com.ys.dto.AddDto;
import com.ys.entity.business.TpBoutique;
import com.ys.entity.business.TpBoutiqueGoods;
import com.ys.entity.finance.TcwAccountCountForCompany;
import com.ys.entity.flow.YspModel;
import com.ys.entity.sys.TsUserChange;
import com.ys.entity.sys.YsMenu;
import com.ys.entity.sys.YsProcInst;
import com.ys.enume.business.TpBoutiqueEnum;
import com.ys.enume.flow.FlowEnum;
import com.ys.enume.flow.YsProcInstEnum;
import com.ys.enume.storage.TccAllocateDetailEnum;
import com.ys.enume.storage.TccAllocateEnum;
import com.ys.enume.storage.TccDistributeEnum;
import com.ys.mapper.storage.StorageMapper;
import com.ys.mapper.storage.TccAllocateDetailMapper;
import com.ys.mapper.storage.TccAllocateMapper;
import com.ys.service.finance.TcwAccountCountForCompanyService;
import com.ys.service.flow.YspTaskService;
import com.ys.service.storage.TccAllocateService;
import com.ys.service.storage.TccDistributeService;
import com.ys.service.sys.CommonApiService;
import com.ys.util.shiro.ShiroUtils;
import com.ys.vo.Flow;
import com.ys.vo.R;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

@Service("tccAllocateService")
public class TccAllocateImpl implements TccAllocateService {

	@Autowired
	private StorageMapper storageMapper;
	@Autowired
	private TccAllocateMapper tccAllocateMapper;
	@Autowired
	private TccAllocateDetailMapper tccAllocateDetailMapper;
	@Autowired
	private TcwAccountCountForCompanyService tcwAccountCountForCompanyService;
	@Autowired
	private TccDistributeService tccDistributeService;
	
	@Autowired
	private CommonApiService<TccDistribute> commonApiService;
	
	@Autowired
	private YspTaskService yspTaskService;

	@Autowired
	private TccPreAllocatePublishMapper tccPreAllocatePublishMapper;
	
	@Override
	@Transactional
	public R checkAccount(String detailArr) {
		
		// 验证详情数据不能为空
		JSONArray detailJA = JSON.parseArray(detailArr);
		if (detailJA == null || detailJA.size() == 0) {
			return R.error("详情数据不能为空");
		}
		/*
		 *  验证详情数据调出调入公司不能为空
		 */
		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			String vgsbmTo = detailJO.getString("vgsbmTo");
			if (vgsbmTo == null || vgsbmTo.length() == 0) {
				return R.error("调入公司编码不能为空");
			}
		}
		
		// 若流程是初始化状态，需要验证账户金额
		Map<String, BigDecimal> VGSBM_AMOUNT_MAP = new HashMap<String, BigDecimal>();
		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			String vgsbmTo = detailJO.getString("vgsbmTo");
			BigDecimal totalPrice = detailJO.getBigDecimal("singlePrice").multiply(detailJO.getBigDecimal("num"));
			if (VGSBM_AMOUNT_MAP.containsKey(vgsbmTo)) {
				VGSBM_AMOUNT_MAP.put(vgsbmTo, VGSBM_AMOUNT_MAP.get(vgsbmTo).add(totalPrice));
			} else {
				VGSBM_AMOUNT_MAP.put(vgsbmTo, totalPrice);
			}
		}
		for(Entry<String, BigDecimal> e : VGSBM_AMOUNT_MAP.entrySet()) {
			String vgsbmTo = e.getKey();
			TcwAccountCountForCompany account = new TcwAccountCountForCompany().setVGsBm(vgsbmTo).queryFirst();
			BigDecimal amountAble = account.getFJe().add(account.getFFzEd()).subtract(account.getFDjJe());
			if (amountAble.compareTo(e.getValue()) < 0) {
				return R.error("【" + vgsbmTo + "】账户可用余额不足，无法流转");
			}
		}
		
		return R.ok();
	}
	
	@Override
	@Transactional(timeout=120,propagation= Propagation.REQUIRES_NEW)
	public R add(String bid, Integer type, String detailArr, Long menuId) throws Exception {
		
		// 验证订单号
		if (new TccAllocate().setBid(bid).count() > 0) {
			return R.error("该订单号已存在");
		}
		
		// 验证详情数据不能为空
		JSONArray detailJA = JSON.parseArray(detailArr);
		if (detailJA == null || detailJA.size() == 0) {
			return R.error("详情数据不能为空");
		}
		
		String loginUserId = ShiroUtils.getUserId();
		/*
		 *  验证详情数据调出调入公司不能为空
		 *  当类型是精品时，验证调入运营公司必须是精品的可见范围
		 */
		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			String vgsbmTo = detailJO.getString("vgsbmTo");
			if (vgsbmTo == null || vgsbmTo.length() == 0) {
				return R.error("调入公司编码不能为空");
			}
			String vgsbmFrom = detailJO.getString("vgsbmFrom");
			if (vgsbmFrom == null || vgsbmFrom.length() == 0) {
				return R.error("调出公司编码不能为空");
			}
			BigDecimal singlePrice = detailJO.getBigDecimal("singlePrice");
			if (singlePrice == null || singlePrice == BigDecimal.ZERO) {
				return R.error("调拨单价不能为空或者为0");
			}
			Integer numTb = detailJO.getInteger("num");
			if (numTb == null || numTb == 0) {
				return R.error("调拨数量不能为空或者为0");
			}
			if (type == TccAllocateEnum.Type.JING_PIN.value) {
				Long boutiqueGoodsId = detailJO.getLong("boutiqueGoodsId");
				if (boutiqueGoodsId == null) {
					return R.error("精品调货信息ID为空");
				}
				TpBoutiqueGoods tpBoutiqueGoods = new TpBoutiqueGoods().setId(boutiqueGoodsId).queryFirst();

				Integer num = new TpBoutique()
						.setCode(tpBoutiqueGoods.getPcode())
						.where("(A.AuthType = " + TpBoutiqueEnum.AuthType.ALL.value + " OR A.Code IN (SELECT AA.BoutiqueCode FROM TP_BoutiqueAuth AA LEFT JOIN THR_OperateCompanyApply BB ON BB.Vgsbm = AA.Vgsbm LEFT JOIN TS_UserChange CC ON CC.Id = BB.OperatorChangeId WHERE CC.UserId = '" + loginUserId + "' AND AA.Vgsbm = '" + vgsbmTo + "'))")
						.count();
				if (num == 0) {
					return R.error("调入公司编码不在精品调拨范围内");
				}
			}
		}
		
		TsUserChange tsUserChange = new TsUserChange().setUserId(loginUserId).setStatus(1).queryFirst();
		
		// 添加预约调拨单
		TccAllocate entity = null;
		{
			Integer effectStock = FlowEnum.EffectStock.NOT_EFFECT.value;
			Long createChangeId = tsUserChange.getId();
			entity = TccAllocate.tccAllocate(bid, effectStock, type, createChangeId, 1);
		}
		tccAllocateMapper.insert(entity);
		
		// 添加预约调拨单明细
		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			
			String bidAllocate = bid;
			String vgsbmFrom = detailJO.getString("vgsbmFrom");
			String vgsjcFrom = detailJO.getString("vgsjcFrom");
			String vgsbmTo = detailJO.getString("vgsbmTo");
			String vgsjcTo = detailJO.getString("vgsjcTo");
			String depotId = detailJO.getString("depotId");
			String depotName = detailJO.getString("depotName");
			String productCode = detailJO.getString("productCode");
			String productName = detailJO.getString("productName");
			BigDecimal singlePrice = detailJO.getBigDecimal("singlePrice");
			Integer num = detailJO.getInteger("num");
			Integer mayDistributeNum = detailJO.getInteger("num");
			Integer preAllocatePublishNum = 0;
			Integer stateDistribute = TccAllocateDetailEnum.StateDistribute.NO.value;
			Long preAllocatePublishItemId = null;
			if (type == TccAllocateEnum.Type.PU_PIN.value) {
				preAllocatePublishItemId = detailJO.getLong("preAllocatePublishItemId");
				TccPreAllocatePublishItem tccPreAllocatePublishItem = new TccPreAllocatePublishItem().setId(preAllocatePublishItemId).queryFirst();
				TccPreAllocatePublish tccPreAllocatePublish  = new TccPreAllocatePublish().setBid(tccPreAllocatePublishItem.getPbid()).queryFirst();
				if (tccPreAllocatePublish.getPublishQuantity().compareTo(new BigDecimal(num).add(tccPreAllocatePublish.getAllocateQuantity())) == -1 ){
					TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
					return R.error(productCode+"该商品可调拨数量不足,请核实后再操作!");
				}
				tccPreAllocatePublish.setAllocateQuantity(tccPreAllocatePublish.getAllocateQuantity().add(new BigDecimal(num)));
				tccPreAllocatePublishMapper.update(tccPreAllocatePublish);
				preAllocatePublishNum = detailJO.getInteger("preAllocatePublishNum");
			}else {
				mayDistributeNum = num;
			}

			TccAllocateDetail tccAllocateDetail = TccAllocateDetail.tccAllocateDetail(bidAllocate, vgsbmFrom, vgsjcFrom, vgsbmTo, vgsjcTo, depotId, depotName, productCode, productName, singlePrice, num, stateDistribute, preAllocatePublishNum,0,mayDistributeNum,0,preAllocatePublishItemId,1);
			tccAllocateDetailMapper.insert(tccAllocateDetail);
		}
		
		/*
		 * 流程初始化
		 */
		YsMenu ysMenu = new YsMenu().setId(menuId).queryFirst();
		if (ysMenu.getFlowModelId().longValue() != 0L) {
			YspModel yspModel = new YspModel().setId(ysMenu.getFlowModelId()).queryFirst();
			String codeModel = yspModel.getCode();
			String createUserId = ShiroUtils.getUserId();
			yspTaskService.init(codeModel, bid, createUserId);
		}
		
		return R.ok(AddDto.gotoEdit("/web/storage/tccAllocate/toFlow?bid=" + entity.getBid()));
	}
	
	@Override
	@Transactional
	public R edit(String bid, String detailArr, Long menuId) throws Exception {
		
		Integer stateFlow = yspTaskService.flowState(bid);
		if (stateFlow != YsProcInstEnum.StateFlow.INIT.value) {
			return R.error("非制单中数据，无法修改");
		}
		
		// 验证是否制单人
		YsProcInst entity = new YsProcInst().setBid(bid).queryFirst();
		if (!entity.getCreateUserId().equals(ShiroUtils.getUserId())) {
			return R.error("非制单人无法修改");
		}
		
		// 验证详情数据不能为空
		JSONArray detailJA = JSON.parseArray(detailArr);
		if (detailJA == null || detailJA.size() == 0) {
			return R.error("详情数据不能为空");
		}
		
		/*
		 *  验证详情数据调出调入公司不能为空
		 */
		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			String vgsbmTo = detailJO.getString("vgsbmTo");
			if (vgsbmTo == null || vgsbmTo.length() == 0) {
				return R.error("调入公司编码不能为空");
			}
			String vgsbmFrom = detailJO.getString("vgsbmFrom");
			if (vgsbmFrom == null || vgsbmFrom.length() == 0) {
				return R.error("调出公司编码不能为空");
			}
			BigDecimal singlePrice = detailJO.getBigDecimal("singlePrice");
			if (singlePrice == null || singlePrice == BigDecimal.ZERO) {
				return R.error("调拨单价不能为空或者为0");
			}
			Integer numTb = detailJO.getInteger("num");
			if (numTb == null || numTb == 0) {
				return R.error("调拨数量不能为空或者为0");
			}
		}
		//修改分配库存
		storageMapper.updatePreAllocatePublish(bid);

		// 删除旧的预约调拨单
		storageMapper.deleteBatchTccAllocateDetailByBid(bid);
		// 添加预约调拨单明细
		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			
			String bidAllocate = bid;
			String vgsbmFrom = detailJO.getString("vgsbmFrom");
			String vgsjcFrom = detailJO.getString("vgsjcFrom");
			String vgsbmTo = detailJO.getString("vgsbmTo");
			String vgsjcTo = detailJO.getString("vgsjcTo");
			String depotId = detailJO.getString("depotId");
			String depotName = detailJO.getString("depotName");
			String productCode = detailJO.getString("productCode");
			String productName = detailJO.getString("productName");
			BigDecimal singlePrice = detailJO.getBigDecimal("singlePrice");
			Integer num = detailJO.getInteger("num");
			Integer mayDistributeNum = detailJO.getInteger("num");
			Integer preAllocatePublishNum = detailJO.getInteger("preAllocatePublishNum");
			Integer stateDistribute = TccAllocateDetailEnum.StateDistribute.NO.value;
			Long preAllocatePublishItemId = detailJO.getLong("preAllocatePublishItemId");
			TccPreAllocatePublishItem tccPreAllocatePublishItem = new TccPreAllocatePublishItem().setId(preAllocatePublishItemId).queryFirst();
			TccPreAllocatePublish tccPreAllocatePublish  = new TccPreAllocatePublish().setBid(tccPreAllocatePublishItem.getPbid()).queryFirst();
			if (tccPreAllocatePublish.getPublishQuantity().compareTo(new BigDecimal(num).add(tccPreAllocatePublish.getAllocateQuantity())) == -1 ){
				TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
				return R.error(productCode+"该商品可调拨数量不足,请核实后再操作!");
			}
			tccPreAllocatePublish.setAllocateQuantity(tccPreAllocatePublish.getAllocateQuantity().add(new BigDecimal(num)));
			tccPreAllocatePublishMapper.update(tccPreAllocatePublish);
			TccAllocateDetail tccAllocateDetail = TccAllocateDetail.tccAllocateDetail(bidAllocate, vgsbmFrom, vgsjcFrom, vgsbmTo, vgsjcTo, depotId, depotName, productCode, productName, singlePrice, num, stateDistribute,preAllocatePublishNum, 0,mayDistributeNum,0,preAllocatePublishItemId,1);
			tccAllocateDetailMapper.insert(tccAllocateDetail);
		}
		
		return R.ok(AddDto.gotoEdit("/web/storage/tccAllocate/toFlow?bid=" + bid));
	}

	@Override
	@Transactional
	public R deleteTrue(Long id) throws Exception {
		if (id == null) {
			return R.error("ID不能为空");
		}
		TccAllocate entity = new TccAllocate().setId(id).queryFirst();
		if (entity.getEffectStock() == FlowEnum.EffectStock.EFFECTED.value) {
			return R.error("已生效数据无法删除");
		}
		// 验证是否制单人
		String loginUserId = ShiroUtils.getUserId();
		TsUserChange tsUserChange = new TsUserChange().setId(entity.getCreateChangeId()).queryFirst();
		
		if (!tsUserChange.getUserId().equals(loginUserId)) {
			return R.error("非制单人，无法删除");
		}
		
		// 删除主数据
		tccAllocateMapper.deleteTrue(id);
		
		// 删除子数据
		List<TccAllocateDetail> listDetail = new TccAllocateDetail().setBidAllocate(entity.getBid()).queryList();
		for(TccAllocateDetail detail : listDetail) {
			tccAllocateDetailMapper.deleteTrue(detail.getId());
			TccPreAllocatePublishItem tccPreAllocatePublishItem = new TccPreAllocatePublishItem().setId(detail.getPreAllocatePublishItemId()).queryFirst();
			TccPreAllocatePublish tccPreAllocatePublish  = new TccPreAllocatePublish().setBid(tccPreAllocatePublishItem.getPbid()).queryFirst();
			tccPreAllocatePublish.setAllocateQuantity(tccPreAllocatePublish.getAllocateQuantity().subtract(new BigDecimal(detail.getNum())));
			tccPreAllocatePublishMapper.update(tccPreAllocatePublish);
		}
		
		yspTaskService.flowDelete(entity.getBid(), loginUserId);
		return R.ok();
	}

	@Override
	@Transactional
	public R flowPass(Long id, String loginUserId) throws Exception {
		
		TccAllocate entity = new TccAllocate().setId(id).queryFirst();
		String bid = entity.getBid();
		
		YsProcInst ysProcInst = new YsProcInst().setBid(bid).queryFirst();
		
		// 若流程是初始化状态，需要验证账户金额
		Map<String, BigDecimal> VGSBM_AMOUNT_MAP = new HashMap<String, BigDecimal>();
		List<TccAllocateDetail> listDetail = new TccAllocateDetail().setBidAllocate(entity.getBid()).queryList();
		if (ysProcInst.getStateFlow() == YsProcInstEnum.StateFlow.INIT.value) {
			for(TccAllocateDetail detail : listDetail) {
				String vgsbmTo = detail.getVgsbmTo();
				BigDecimal totalPrice = detail.getSinglePrice().multiply(new BigDecimal(detail.getNum()));
				if (VGSBM_AMOUNT_MAP.containsKey(vgsbmTo)) {
					VGSBM_AMOUNT_MAP.put(vgsbmTo, VGSBM_AMOUNT_MAP.get(vgsbmTo).add(totalPrice));
				} else {
					VGSBM_AMOUNT_MAP.put(vgsbmTo, totalPrice);
				}
			}
			for(Entry<String, BigDecimal> e : VGSBM_AMOUNT_MAP.entrySet()) {
				String vgsbmTo = e.getKey();
				TcwAccountCountForCompany account = new TcwAccountCountForCompany().setVGsBm(vgsbmTo).queryFirst();
				BigDecimal amountAble = account.getFJe().add(account.getFFzEd()).subtract(account.getFDjJe());
				if (amountAble.compareTo(e.getValue()) < 0) {
					return R.error("【" + vgsbmTo + "】账户可用余额不足，无法流转");
				}
			}
		}
		
		try {
			Flow f = yspTaskService.flowPass(bid, loginUserId);
			if (f.getCode() == Flow.Code.FAILED.value) {
				return R.error(f.getMsg());
			} else {
				// 若是制单流转，冻结账户
				if (ysProcInst.getStateFlow() == YsProcInstEnum.StateFlow.INIT.value) {
					for(TccAllocateDetail detail : listDetail) {
						String vgsbm = detail.getVgsbmTo();
						BigDecimal amount = detail.getSinglePrice().multiply(new BigDecimal(detail.getNum()));
						tcwAccountCountForCompanyService.frozen(vgsbm, amount,
								TcwOperateFrozenRunningEnum.DocumentType.TCC_Allocate.value,
								detail.getId(),
								entity.getBid(),
								null);
					}
				}
				
				if (f.getState() == Flow.State.FINISH.value) {
					flowFinish(id, loginUserId);
				}
				return R.ok();
			}
		} catch (Exception e) {
			e.printStackTrace();
			return R.error("服务器正在开小差，请联系客服");
		}
	}

	@Override
	public R flowRefuse(Long id, String reason, String loginUserId) throws Exception {
		
		TccAllocate entity = new TccAllocate().setId(id).queryFirst();
		String bid = entity.getBid();
		
		R r = yspTaskService.flowRefuse(bid, reason, loginUserId);
		
		if (r.getCode() == R.Code.SUCCESS.value) {
			YsProcInst ysProcInst = new YsProcInst().setBid(bid).queryFirst();
			// 若退回到制单状态，则解冻账户
			if (ysProcInst.getStateFlow() == YsProcInstEnum.StateFlow.INIT.value) {
				List<TccAllocateDetail> listDetail = new TccAllocateDetail().setBidAllocate(entity.getBid()).queryList();
				for(TccAllocateDetail detail : listDetail) {
					String vgsbm = detail.getVgsbmTo();
					BigDecimal amount = detail.getSinglePrice().multiply(new BigDecimal(detail.getNum()));
					tcwAccountCountForCompanyService.thaw(vgsbm, amount,
							TcwOperateFrozenRunningEnum.DocumentType.TCC_Allocate.value,
							detail.getId(),
							entity.getBid(),
							null);
				}
			}
		}
		return r;
	}


	@Override
	public R flowInit(Long id, String reason, String loginUserId) throws Exception {

		TccAllocate entity = new TccAllocate().setId(id).queryFirst();
		String bid = entity.getBid();

		R r = yspTaskService.flowInit(bid, reason, loginUserId);

		if (r.getCode() == R.Code.SUCCESS.value) {
			YsProcInst ysProcInst = new YsProcInst().setBid(bid).queryFirst();
			// 若退回到制单状态，则解冻账户
			if (ysProcInst.getStateFlow() == YsProcInstEnum.StateFlow.INIT.value) {
				List<TccAllocateDetail> listDetail = new TccAllocateDetail().setBidAllocate(entity.getBid()).queryList();
				for(TccAllocateDetail detail : listDetail) {
					String vgsbm = detail.getVgsbmTo();
					BigDecimal amount = detail.getSinglePrice().multiply(new BigDecimal(detail.getNum()));
					tcwAccountCountForCompanyService.thaw(vgsbm, amount,
							TcwOperateFrozenRunningEnum.DocumentType.TCC_Allocate.value,
							detail.getId(),
							entity.getBid(),
							null);
				}
			}
		}
		return r;
	}

	@Override
	@Transactional
	public void flowFinish(Long id, String loginUserId) throws Exception {
		
		TccAllocate entity = new TccAllocate().setId(id).queryFirst();
		
		YsProcInst ysProcInst = new YsProcInst().setBid(entity.getBid()).queryFirst();
		if (ysProcInst.getStateFlow() != YsProcInstEnum.StateFlow.FINISH.value) {
			return;
		}
		
		entity.setEffectStock(FlowEnum.EffectStock.EFFECTED.value);
		tccAllocateMapper.update(entity);

	}

	@Override
	public R hasAllocated(Long id) {
		TpBoutique tpBoutique = new TpBoutique().setId(id).queryFirst();
		if (id == null) {
			return R.error("ID不能为空");
		}
		String loginUserId = ShiroUtils.getUserId();
		Integer numAllocate = new TccAllocateDetail()
				.setProductCode(tpBoutique.getCode())
				.addLeftJoin("TCC_Allocate B on B.Bid = A.BidAllocate")
				.where("B.EffectStock = " + FlowEnum.EffectStock.EFFECTED.value)
				.where(loginUserId.equals("admin") ? "1=1" : "A.VgsbmTo in (select VGsBm from THR_OperateCompanyApply where CUser = '" + loginUserId + "')")
				.count();
		
		Integer numAllot = new TccStockAllot()
				.setProductCode(tpBoutique.getCode())
				.setEffectStock(FlowEnum.EffectStock.EFFECTED.value)
				.where(loginUserId.equals("admin") ? "1=1" : "A.ToGClient in (select VGsBm from THR_OperateCompanyApply where CUser = '" + loginUserId + "')")
				.count();
		
		
		if (numAllocate == 0 && numAllot == 0) {
			return R.error("尚未调拨");
		}
		return R.ok();
	}

	//获取子列表数据
	@Override
	@Transactional
	public List<Map<String, Object>> getItemList( String bid) throws Exception{
		List<Map<String, Object>> sonlist = new TccAllocateDetail()
				.setBidAllocate(bid)
				.addField("(A.singlePrice * A.Num) totalPrice")
				.queryMap();
		return sonlist;
	}



}
